// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 

using System;
using System.Collections.Generic;

using Galaxium.Protocol.Xmpp.Library.Core;

namespace Galaxium.Protocol.Xmpp.Library
{
	public enum EntryDirection { In, Out }
	
	public class LogEntry
	{
		internal LogEntry (Stanza stanza, EntryDirection dir)
		{
			Stanza = stanza;
			Direction = dir;
		}
		
		public Stanza Stanza { get; private set; }
		public EntryDirection Direction { get; private set; }
	}
	
	public class LogEventArgs: EventArgs
	{
		public JabberID Jid { get; private set; }
		public Stanza Stanza { get; private set; }
		public EntryDirection Direction { get; private set; }
		
		public LogEventArgs (JabberID jid, Stanza stanza, EntryDirection dir)
		{
			Jid = jid;
			Stanza = stanza;
			Direction = dir;
		}
	}
	
#if DEBUG
	
	public class ProtocolLog
	{
		public event EventHandler<LogEventArgs> StanzaLogged;
		
		CoreStream _stream;
		private Dictionary<JabberID, List<LogEntry>> _logs;
		
		public ProtocolLog (CoreStream stream)
		{
			_logs = new Dictionary<JabberID, List<LogEntry>> ();
			_stream = stream;
			_stream.StanzaReceived += HandleStanzaReceived;
			_stream.StanzaSent += HandleStanzaSent;
		}

		~ProtocolLog ()
		{
			_stream.StanzaReceived -= HandleStanzaReceived;
			_stream.StanzaSent -= HandleStanzaSent;
		}

		void HandleStanzaSent (object sender, StanzaEventArgs e)
		{
			var stanza = e.Stanza.Clone () as Stanza;
			
			var jid = (stanza.To ?? JabberID.Empty).Bare ();
			if (jid == _stream.UID || jid == _stream.UID.Bare () ||
			    (jid.Domain == _stream.UID.Domain && jid.Node == null))
				jid = JabberID.Empty;
			AddLogEntry (jid, new LogEntry (stanza, EntryDirection.Out));
			OnStanzaLogged (jid, stanza, EntryDirection.Out);
		}

		void HandleStanzaReceived (object sender, StanzaEventArgs e)
		{
			var stanza = e.Stanza.Clone () as Stanza;
			
			var jid = (stanza.From ?? JabberID.Empty).Bare ();
			if (jid == _stream.UID || jid == _stream.UID.Bare () ||
			    (jid.Domain == _stream.UID.Domain && jid.Node == null))
				jid = JabberID.Empty;
			AddLogEntry (jid, new LogEntry (stanza, EntryDirection.In));
			OnStanzaLogged (jid, stanza, EntryDirection.In);
		}

		private void AddLogEntry (JabberID jid, LogEntry entry)
		{
			List<LogEntry> log;
			if (!_logs.TryGetValue (jid, out log))
				_logs [jid] = log = new List<LogEntry> ();
			log.Add (entry);
		}	
		
		private void OnStanzaLogged (JabberID jid, Stanza stanza, EntryDirection dir)
		{
			if (StanzaLogged != null)
				StanzaLogged (this, new LogEventArgs (jid, stanza, dir));
		}

		public IEnumerable<LogEntry> GetLog (JabberID jid)
		{
			List<LogEntry> log;
			return _logs.TryGetValue (jid, out log) ? log : null;
		}
	}
	
#else
	
	public class ProtocolLog
	{
		public event EventHandler<LogEventArgs> StanzaLogged;
		public ProtocolLog (CoreStream stream) {}
		public IEnumerable<LogEntry> GetLog (JabberID jid) { return null; }
	}
	
#endif
	
}
